#ifndef __PROFILE_H
#define __PROFILE_H

#include <time.h>

#include "dbg.h"
#include "sysutil.h"


#define PROFILE_POINT_MAX 10

/**
 * 函数的一阶段
 */
typedef struct {
        uint64_t count;
        uint64_t total;
        uint64_t max;

        // struct timeval t;
        // int64_t used;
} profile_point_t;

/**
 * 函数
 */
typedef struct {
        int inited;
        char name[256];
        uint64_t count;       //!< 进入了多少次
        int enter;
        int freq;
        int stage;            //!< 总的阶段数, 0-based
        profile_point_t points[PROFILE_POINT_MAX];
} profile_t;


static inline int profile_begin0(profile_t *profile, const char *name, int stage, int freq) {
        // profile_point_t *point;
        profile->enter++;

        if (!profile->inited) {
                memset(profile, 0x0, sizeof(profile_t));

                strcpy(profile->name, name);
                profile->count = 0;
                profile->freq = freq;
                profile->stage = stage;

                // point = &profile->points[0];

                // point->count = 0;
                // point->total = 0;
                // point->max = 0;

                profile->inited = 1;
        }

        return 0;
}

static inline int profile_begin(profile_t *profile, const char *name, int stage) {
        return profile_begin0(profile, name, stage, 100);
}

/**
 * @note 并发场景
 *
 * @param profile
 * @param stage
 * @param used
 * @return
 */
static inline int profile_collect(profile_t *profile, int stage, int64_t used) {
        profile_point_t *point;

        YASSERT(stage > 0 && stage <= PROFILE_POINT_MAX);

        point = &profile->points[stage-1];

        point->count++;
        point->total += used;
        if (point->max < used) {
                point->max = used;
        }

        return 0;
}

static inline int profile_end(profile_t *profile, int stage) {
        profile_point_t *point;

        YASSERT(stage == profile->stage);

        profile->count++;
        if (profile->count % profile->freq == 0) {
                for (int i=0; i < stage; i++) {
                        point = &profile->points[i];
                        DINFO("name %s/%ju enter %d stage %d %10jd %15jd %10jd %10jd\n",
                              profile->name,
                              profile->count,
                              profile->enter,
                              i + 1,
                              point->count,
                              point->total,
                              point->total / point->count,
                              point->max);
                }
        }

        profile->enter--;
        return 0;
}

#if ENABLE_PROFILE

#define PROFILE_BEGIN(stage) \
        static profile_t aProfile; \
        static profile_t *profile = &aProfile; \
        struct timeval __t[(stage)+1]; \
        memset(__t, 0x0, sizeof(__t)); \
        int64_t __used[(stage)]; \
        \
        _gettimeofday(&__t[0], NULL); \
        profile_begin((profile), __FUNCTION__, (stage))

#define PROFILE_COLLECT(__stage) \
        _gettimeofday(&__t[__stage], NULL); \
        __used[__stage-1] = _time_used(&__t[__stage-1], &__t[__stage]); \
        profile_collect((profile), __stage, __used[__stage-1]); \
        if (__stage == profile->stage) { \
                profile_end(profile, __stage); \
        }

#define PROFILE_SKIP(__stage) \
        if (__t[__stage].tv_sec == 0) { \
                _gettimeofday(&__t[__stage], NULL); \
        }

#else

#define PROFILE_BEGIN(stage) do {} while(0)
#define PROFILE_COLLECT(stage) do {} while(0)
#define PROFILE_SKIP(stage) do {} while(0)

#endif

#endif
